package com.sinder.campus_prophet.service.general.impl;

import com.alibaba.fastjson.JSONObject;
import com.sinder.campus_prophet.core.enums.WeChat;
import com.sinder.campus_prophet.entity.general.TbWxToken;
import com.sinder.campus_prophet.exception.WxApiException;
import com.sinder.campus_prophet.mapper.general.TbWxTokenMapper;
import com.sinder.campus_prophet.service.general.WxApiService;
import com.sinder.campus_prophet.utils.IsNotExits;
import com.sinder.campus_prophet.utils.WebHttpClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 微信小程序实现接口
 * @author v-xyingde
 * @date 2023/3/16/14:33
 */
@Service
@Slf4j
public class WxApiServiceImpl implements WxApiService {
    private final TbWxTokenMapper tokenMapper;

    private final WebHttpClient wxClient;

    public WxApiServiceImpl(TbWxTokenMapper tokenMapper, WebHttpClient wxClient) {
        this.tokenMapper = tokenMapper;
        this.wxClient = wxClient;
    }

    /**
     * 根据code获取openId
     * @param code
     * @return
     */
    @Override
    public Map<String, String> getWxOpenId(String code) {
        // 构建请求参数
        MultiValueMap<String, String> param = new LinkedMultiValueMap<>(4);
        param.add("appid", WeChat.APP_ID);
        param.add("secret", WeChat.APP_SECRET);
        param.add("js_code", code);
        param.add("grant_type", WeChat.WX_LOGIN_GRANT_TYPE);
        // 构建请求
        Map<String, String> map = new HashMap<>();
        try {
            Mono<String> mono = wxClient.wxGet(WeChat.WX_LOGIN_URL, param, String.class);

            JSONObject wxResult = JSONObject.parseObject(mono.block());
            log.info("微信服务返回信息 === " + wxResult);
            if (wxResult.containsKey("openid")) {
                // 存在openId 返回openId
                String session_key = wxResult.get("session_key").toString();
                String open_id = wxResult.get("openid").toString();
                map.put("openId", open_id);
                map.put("sessionKey", session_key);
            } else {
                // 返回微信提供的错误信息
                map.put("error", wxResult.get("errmsg").toString());
            }
        } catch (WebClientRequestException e) {
            throw new WxApiException("微信服务接口调用异常：" + e.getMessage() + ";url：" + e.getUri());
        }
        return map;
    }

    /**
     * 获取access_token
     * 使用synchronized修饰，然后token保存在库表中，根据时效性提取
     * @return
     */
    @Override
    public synchronized Map<String, String> getAccessToken() {
        // 设定容器储存数据
        Map<String, String> map = new HashMap<>();
        // 检验是否存在可用token
        String token = tokenMapper.checkToken();
        if (IsNotExits.isNotValue(token)) {
            // token已过期，需要重新获取并入库
            // 配置请求参数
            MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
            param.add("appid", WeChat.APP_ID);
            param.add("secret", WeChat.APP_SECRET);
            param.add("grant_type", WeChat.WX_ACCESS_TOKEN_TYPE);
            // 向微信第三方服务发送请求
            try {
                Mono<JSONObject> mono = wxClient.wxGet(WeChat.WX_TOKEN_URL, param, JSONObject.class);
                JSONObject wxResult = mono.block();
                log.info("微信服务返回信息 === " + wxResult);
                if (wxResult != null && wxResult.containsKey("access_token")) {
                    // 存在access_token 返回access_token，并设置入库
                    String access_token = wxResult.get("access_token").toString();
                    TbWxToken wxToken = new TbWxToken();
                    wxToken.setId(1);
                    wxToken.setAccessToken(access_token);
                    wxToken.setCreateTime(new Date());
                    tokenMapper.updateById(wxToken); // 更新token
                    map.put("access_token", access_token);
                    return map;
                }
                // 返回微信提供的错误信息
                log.error("微信服务接口返回异常信息：" + Objects.requireNonNull(wxResult).get("errmsg").toString());
                throw new WxApiException("微信服务接口返回异常信息：" + wxResult.get("errmsg").toString());
            } catch (WebClientRequestException e) {
                throw new WxApiException("微信服务接口调用异常：" + e.getMessage() + ";url：" + e.getUri());
            }
        }
        map.put("access_token", token);
        return map;
    }
}
